#import "ToyView.h"
#import <dpsclient/wraps.h>
#import <appkit/publicWraps.h>
#import <appkit/NXImage.h>
#import <appkit/NXBitmapImageRep.h>
#import <appkit/Application.h>
#import <appkit/NXCursor.h>
#import <appkit/TextField.h>
#import <stdlib.h>
#import "PrefControl.h"

#define  CrossCursor	"cross.tiff"

static NXCursor *xCursor = nil;
static BOOL originUpperLeft = NO;


@implementation ToyView (EventHandling)

+ cursor
{
    if (!xCursor) {
	NXPoint spot;
	xCursor = [NXCursor newFromImage:[NXImage newFromSection:CrossCursor]];
	spot.x = 7.0; spot.y = 7.0;
	[xCursor setHotSpot:&spot];
    }
    return xCursor;
}

- (BOOL)acceptsFirstResponder
{
    return YES;
}

- (BOOL)acceptsFirstMouse
{
    return YES;
}

- resetCursorRects
{
	NXRect visible;

	if ([self getVisibleRect:&visible])
		[self addCursorRect:&visible cursor:xCursor];
	return self;
}

/* Local Method */
- drawDraggedLine: (NXCoord)x : (NXCoord)y : (int)dx : (int)dy
{
	char	buf[20], points[64];
	int	y1, y2;

	if (originUpperLeft) {
		y1 = curSize.height - y - dy;
		y2 = curSize.height - y - 1;
	}else {
		y1 = y,  y2 = y + dy - 1;
	}
	sprintf(points, "%d x %d  (%d, %d : %d, %d)",
			dx, dy, (int)x, y1, (int)x + dx - 1, y2);
	[commText setStringValue: points];

	// already 'lockFocus'ed
	PSnewinstance();
	PSsetinstance(YES);
	PSsetlinewidth(0.0);
	PSsetgray(0.1667);
	PSrectstroke(x, y+1, dx-1, dy-1);	/* Why +1 ?? */
	if ( dx >= 18 && dy >= 10 ) {
		sprintf(buf, "%d x %d", dx, dy);
		PSmoveto(x+1, y+2);
		PSgsave();
		PSscale(1.0, -1.0);
		PSshow(buf);
		PSgrestore();
	}
	PSsetinstance(NO);
	NXPing();
	return self;
}

- clearDraggedLine
{
	NXSize *sz = &selectRect.size;
	if (sz->width > 0.0 || sz->height > 0.0) {
		[self lockFocus];
		PSnewinstance();
		[self unlockFocus];
		sz->width = 0.0;
		sz->height = 0.0;
		[commText setStringValue: comInfo->memo];
	}
	return self;
}

- setDraggedLine: sender
{
	NXSize *sz = &selectRect.size;
	if (sz->width > 0.0 && sz->height > 0.0) {
		[self lockFocus];
		[self drawDraggedLine: selectRect.origin.x
			: selectRect.origin.y : sz->width : sz->height];
		[self unlockFocus];
	}
	return self;
}


/* Code from pCD.app (H. Danisch & D. Phillips) */

#define DRAG_MASK (NX_MOUSEUPMASK|NX_MOUSEDRAGGEDMASK)
- mouseDown:(NXEvent *)event
{
	NXPoint	p, start, lowerleft;
	BOOL	altDrag = NO, sftDrag = NO;
	int	oldMask;
	int	xn = 0, yn = 0, xs, ys;

	originUpperLeft = [preference originUpperLeft];
	oldMask = [window addToEventMask:NX_MOUSEDRAGGEDMASK|NX_MOUSEUPMASK];
	p = event->location;
	[self convertPoint:&p fromView:nil]; /* View based point */
	if (p.x < 0.0) p.x = 0.0;
	else if (p.x >= curSize.width) p.x = curSize.width - 1;
	p.y--;
	if (p.y < 0.0) p.y = 0.0;
	else if (p.y > curSize.height) p.y = curSize.height - 1;
	start.x = (int)p.x;
	start.y = (int)p.y;
	if (NX_ALTERNATEMASK &  event->flags)
		altDrag = YES;

	[self lockFocus];
	PSnewinstance();
	PSsetinstance(YES);
	event = [NXApp getNextEvent:DRAG_MASK];

	while( event->type != NX_MOUSEUP ) {
		if (NX_ALTERNATEMASK &  event->flags)
			altDrag = YES;
		if (NX_SHIFTMASK &  event->flags)
			sftDrag = YES;
		p = event->location;
		[self convertPoint:&p fromView:nil];
		if (p.x < 0.0) p.x = 0.0;
		else if (p.x >= curSize.width) p.x = curSize.width - 1;
		p.y--;
		if (p.y < 0.0) p.y = 0.0;
		else if (p.y > curSize.height) p.y = curSize.height - 1;

		if (p.x > start.x)
			xn = (int)p.x - start.x + 1,  xs = 1;
		else
			xn = start.x - (int)p.x + 1,  xs = -1;
		if (p.y > start.y)
			yn = (int)p.y - start.y + 1,  ys = 1;
		else
			yn = start.y - (int)p.y + 1,  ys = -1;
		if (altDrag) {
			if (xn < yn) yn = xn;
			else xn = yn;
		}
		if (sftDrag) {
			xn = (xn + 1) & ~3;
			yn = (yn + 1) & ~3;
		}
		p.x = start.x + (xn-1)*xs;
		p.y = start.y + (yn-1)*ys;
		lowerleft.x = (start.x < p.x) ? start.x : p.x;
		lowerleft.y = (start.y < p.y) ? start.y : p.y;
		[self drawDraggedLine: lowerleft.x : lowerleft.y : xn : yn];
		event = [NXApp getNextEvent:DRAG_MASK];
	}
	[self unlockFocus];
	    
	selectRect.origin.x = lowerleft.x;
	selectRect.origin.y = lowerleft.y;
	selectRect.size.width  = xn;
	selectRect.size.height = yn;
	if (xn == 0 && yn == 0)		/* only click */
		[commText setStringValue: comInfo->memo];
	else if (xn < 3 && yn < 3)	/* Too small area */
		[self clearDraggedLine];

	[window flushWindow];
	[window setEventMask:oldMask];

	return self;
}

- selectAll:sender
{
	[self clearDraggedLine];
	selectRect.size = curSize;
	selectRect.origin.x = selectRect.origin.y = 0.0;
	[self setDraggedLine: sender];
	return self;
}

- copy:sender
{
	NXStream	*st;
	NXBitmapImageRep *bm;
	int		i = 0;
	const char	*types[2];
	id		pb = [Pasteboard new];

	if (selectRect.size.width < 1.0 || selectRect.size.height < 1.0) {
		NXBeep();
		return self;
	}

	//  note that "owner:" in the following can not be "self", or the
	//  id of anything else which might be freed inbetween "Copy"
	//  operations.
	types[i++] = NXTIFFPboardType;
	[pb declareTypes:types num:i owner:NXApp];

	[self lockFocus];
	bm = [[NXBitmapImageRep alloc] initData:NULL fromRect:&selectRect];
	[self unlockFocus];

	st = NXOpenMemory(NULL, 0, NX_WRITEONLY);
	[bm writeTIFF:st];
	[pb writeType:NXTIFFPboardType fromStream:st];
	NXCloseMemory(st, NX_FREEBUFFER);
	[bm free];

	return self;
}

- drawSelf:(NXRect *)r :(int) count
{
	NXSize *sz;

	if (comInfo->alpha) {
		PSsetgray(1.0);	
		NXRectFill(r);
		[image composite:NX_SOVER fromRect:r toPoint:&(r->origin)];
	}else
		[image composite:NX_COPY fromRect:r toPoint:&(r->origin)];

	sz = &selectRect.size;
	if (sz->width > 0.0 && sz->height > 0.0)
		[self perform:@selector(setDraggedLine:) with:self
		afterDelay:30 cancelPrevious:YES];
	return self;
}

@end
